#include "AdministradorEstadisticas.h"

AdministradorEstadisticas::AdministradorEstadisticas(bool atachado) :
		Thread(atachado) {
	this->colorfuente = {0xFF, 0xFF, 0xFF};
}

void AdministradorEstadisticas::signalHandler(int signal){
	switch (signal){
	case SIGUSR1:
		pthread_exit(NULL);
	}
}

AdministradorEstadisticas::~AdministradorEstadisticas() {
}

void AdministradorEstadisticas::run() {
	signal(SIGUSR1, AdministradorEstadisticas::signalHandler);
	this->iniciarVideo();
	while (!this->torneo->isFinalizado()) {
		this->actualizarPartidas();
		this->actualizarEstadisticas();
		this->mostrarEstadisticas();
		usleep(100000);
	}
}

void AdministradorEstadisticas::actualizarPartidas() {
	t_partida aux;
	this->torneo->getMutexPartidas()->P();
	std::list<t_partida>::iterator it = this->torneo->getPartidas().begin();
	for ( ; it != this->torneo->getPartidas().end(); ++it) {
		/* Solo toma partidas activas */
		if(it->activo){
			aux = this->torneo->getAdministradorMemoriaCompartida()->leerDatos(it->partidaId);
			it->jugador1.puntaje = aux.jugador1.puntaje;
			it->jugador2.puntaje = aux.jugador2.puntaje;
			it->jugador1.conectado = aux.jugador1.conectado;
			it->jugador2.conectado = aux.jugador2.conectado;
		}
	}
	this->torneo->getMutexPartidas()->V();
}
//////////////////////////////////ORDENMIENTO DE LISTAS//////////////////////////////////////////

void AdministradorEstadisticas::actualizarEstadisticas() {
	this->torneo->getMutexPartidas()->P();
	std::list<t_partida>::iterator it = this->torneo->getPartidas().begin();
	for ( ; it != this->torneo->getPartidas().end(); ++it) {
		actualizarRanking(it);
	}
	actualizarPosiciones();
	it = this->torneo->getPartidas().begin();
	for ( ; it != this->torneo->getPartidas().end(); ++it) {
		if(it->activo){
			actualizarRankingEnPartida((t_partida *) &(*it) );
			this->torneo->getAdministradorMemoriaCompartida()->escribirDatos(&(*it), it->partidaId);
		}
	}
	this->torneo->getMutexPartidas()->V();
}

void AdministradorEstadisticas::actualizarRankingEnPartida(t_partida * partida){
	this->torneo->getMutexRanking()->P();
	std::list<t_estadistica_jugador>::iterator it = this->torneo->getRanking()->begin();
	for ( ; it != this->torneo->getRanking()->end(); ++it) {
		if(partida->jugador1.socket_id == it->jugador.socket_id){
			partida->jugador1.ranking = it->jugador.ranking;
		}
		if(partida->jugador2.socket_id == it->jugador.socket_id){
			partida->jugador2.ranking = it->jugador.ranking;
		}
	}
	this->torneo->getRanking()->sort(AdministradorEstadisticas::compararJugadoresPorPromedio);
	this->torneo->getMutexRanking()->V();
}

void AdministradorEstadisticas::actualizarRanking(std::list<t_partida>::iterator iteradorPartidas) {
	this->torneo->getMutexRanking()->P();
	std::list<t_estadistica_jugador>::iterator it = this->torneo->getRanking()->begin();
	for ( ; it != this->torneo->getRanking()->end(); ++it) {
		this->actualizarJugadorRanking(&(iteradorPartidas->jugador1), iteradorPartidas->partidaId, it);
		this->actualizarJugadorRanking(&(iteradorPartidas->jugador2), iteradorPartidas->partidaId, it);
	}
	this->torneo->getRanking()->sort(AdministradorEstadisticas::compararJugadoresPorPromedio);
	this->torneo->getMutexRanking()->V();
}

void AdministradorEstadisticas::actualizarJugadorRanking(t_jugador* jugadorPartida, long int partidaId, std::list<t_estadistica_jugador>::iterator iteradorRanking) {
	if (jugadorPartida->socket_id == iteradorRanking->jugador.socket_id) {
		iteradorRanking->total_puntaje = 0;
		std::map<int, long int>::iterator it;
		for (it = iteradorRanking->partidas_puntajes.begin(); it != iteradorRanking->partidas_puntajes.end(); ++it) {
			if (it->first == partidaId) {
				it->second = jugadorPartida->puntaje;
				iteradorRanking->total_puntaje = iteradorRanking->total_puntaje + it->second;
			}
		}
	}
}

void AdministradorEstadisticas::actualizarPosiciones() {
	int i=0;
	std::list<t_estadistica_jugador>::iterator it= this->torneo->getRanking()->begin();
	for ( ; it != this->torneo->getRanking()->end(); ++it) {
		i++;
		it->jugador.ranking = i;
	}
}

bool AdministradorEstadisticas::compararJugadoresPorPromedio(const t_estadistica_jugador &lej, const t_estadistica_jugador &rej) {
	float left = ((float) lej.total_puntaje / (float) lej.partidas_puntajes.size());
	float right= ((float) rej.total_puntaje / (float) rej.partidas_puntajes.size());
	return  (left > right);
}

//////////////////////////////// PANTALLA ///////////////////////////////////////////////

void AdministradorEstadisticas::mostrarEstadisticas() {
	char valor[50];
//	int tiempo = 0;
//	cargaTitulos(2);
//	SDL_FreeSurface( pantalla );
	time_t* tiempoActual = this->torneo->getTiempoActual();
	int minutos = *tiempoActual / 60;
	int segundos = *tiempoActual % 60;
	// fecha_hora->tm_min; minuto
	// fecha_hora->tm_sec; segundos
	apply_surface(0, 0, this->background, this->pantalla, NULL);
	ostringstream ss;
	ss << minutos << ":" << segundos;
	/* Abre la fuente a utilizar */
	ttext = TTF_RenderText_Solid(fuente3, ss.str().c_str(), colorfuente);
	apply_surface(550, 0, ttext, this->pantalla, NULL);
	y = 30;
	this->torneo->getMutexRanking()->P();
	std::list<t_estadistica_jugador>::iterator it = this->torneo->getRanking()->begin();
	for (; it != this->torneo->getRanking()->end(); ++it) {
		// obtengo el nombre del jugador1 de una partida
		cadena = it->jugador.nombre;
		ttext = TTF_RenderText_Solid(fuente3, cadena.c_str(), colorfuente);
		apply_surface(190, y, ttext, this->pantalla, NULL);
		// obtengo el ranking del jugador
		sprintf(valor, "%02d", it->jugador.ranking);
		ttext = TTF_RenderText_Solid(fuente3, valor, colorfuente);
		apply_surface(340, y, ttext, this->pantalla, NULL);
		// obtengo los puntos totales del jugador
		sprintf(valor, "%0ld", it->total_puntaje);
		ttext = TTF_RenderText_Solid(fuente3, valor, colorfuente);
		apply_surface(390, y, ttext, this->pantalla, NULL);

		//incremento la posicion de y
		y += TAM3;
	}
	this->torneo->getMutexRanking()->V();
	SDL_Flip(this->pantalla);
}
/*
 void AdministradorEstadisticas::cargaTitulos(int seleccion) {
 cadena = "ESTADISTICAS";
 SDL_FillRect(pantalla, NULL, SDL_MapRGB(pantalla->format, 0, 0, 0));
 imagen = IMG_Load("./ImagenesFuentes/menu.png");

 imagen = SDL_DisplayFormatAlpha(imagen);
 rect.x = 0;
 rect.y = 0;
 rect.w = 0;
 rect.h = 0;
 SDL_BlitSurface(imagen, NULL, pantalla, &rect);

 //SDL_Flip(pantalla);

 ttext = TTF_RenderText_Solid(fuente1, cadena.c_str(), colorfuente);
 rect.x = 300;
 rect.y = 10;
 SDL_BlitSurface(ttext, NULL, pantalla, &rect);

 //inicializo la posicion de y
 y = TAM1 + 10;

 //doy formato y coloco los textos de la pantalla
 cadena = "Posiciones   |   ";
 if (seleccion == 1)
 ttext = TTF_RenderText_Solid(fuente2, cadena.c_str(), colorfuente);
 else if (seleccion == 2)
 ttext = TTF_RenderText_Solid(fuente2, cadena.c_str(), colorfuente2);
 rect.x = 245;
 rect.y = y;
 SDL_BlitSurface(ttext, NULL, pantalla, &rect);

 cadena = "  Partidas Jugadas";
 if (seleccion == 1)
 ttext = TTF_RenderText_Solid(fuente2, cadena.c_str(), colorfuente2);
 else if (seleccion == 2)
 ttext = TTF_RenderText_Solid(fuente2, cadena.c_str(), colorfuente);
 rect.x = 370;
 rect.y = y;
 SDL_BlitSurface(ttext, NULL, pantalla, &rect);

 cadena = "(Presione la tecla P para cambiar de informe y Esc para salir.)";
 ttext = TTF_RenderText_Solid(fuente3, cadena.c_str(), colorfuente);
 rect.x = 145;
 rect.y = y + TAM2;
 SDL_BlitSurface(ttext, NULL, pantalla, &rect);

 y += TAM2 * 3; //incremento la posicion de y

 }
 */

/* Inicia la pantalla con la configuracion y las imagenes base */
bool AdministradorEstadisticas::iniciarVideo() {
	this->y = 30;
	/* Inicia la pantalla de video */
	if (SDL_Init(SDL_INIT_VIDEO) != 0) {
		cout << " [ERROR] No se pudo levantar la imagen del local: " << SDL_GetError() << endl;
		return false;
	}

	/* Inicializo las fuentes sdls */
	if (TTF_Init() == -1) {
		cout << " [ERROR] No se pudieron levantar las fuentes" << SDL_GetError() << endl;
		return false;
	}

	/*De esta forma me aseguro que al cerrarse el programa se cierren también todos
	 los subsitemas de SDL*/
	atexit(SDL_Quit);

	/*Inicializo el modo de video con una pantalla de 800 x 600 con 32 bytes de
	 profundidad de color  LO CAMBIE a 16 no sera mas rapido asi??*/
	pantalla = SDL_SetVideoMode(800, 600, 16, 0);
	if (pantalla == NULL) {
		cout << " [ERROR] No se pudo inicializar el modo de video: " << SDL_GetError() << endl;
		return false;
	}

	//Bloqueo el uso de la superficie
	SDL_LockSurface(pantalla);

	/* Abre la fuente a utilizar */
	fuente3 = TTF_OpenFont("fuente.ttf", 16);
	if (fuente3 == NULL) {
		return false;
	}

	/* Cargo el fondo de pantalla inicial */
	background = load_image("background.bmp");
	if (background == NULL) {
		cout << " [ERROR] No se pudo levantar la imagen del visitante: " << SDL_GetError() << endl;
		return false;
	}

	//Ignoro los eventos que no uso
	SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
	SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_IGNORE);
	SDL_EventState(SDL_MOUSEBUTTONUP, SDL_IGNORE);
	SDL_EventState(SDL_KEYUP, SDL_IGNORE);

	//Set the window caption
	//SDL_WM_SetCaption( "High Score", NULL );

	//Desbloqueo la superficie
	SDL_UnlockSurface(pantalla);

	/* Update the screen */
	this->apply_surface(0, 0, background, pantalla, NULL);
	if (SDL_Flip(pantalla) == -1) {
		return 1;
	}

	return true;
}

/*  Aplica una superficie sobre una pantalla base o otra superficie */
void AdministradorEstadisticas::apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip) {
	//Holds offsets
	SDL_Rect offset;

	//Get offsets
	offset.x = x;
	offset.y = y;

	//Blit
	SDL_BlitSurface(source, clip, destination, &offset);
}

/* Carga una imagen en una superficie */
SDL_Surface *AdministradorEstadisticas::load_image(const char *path) {
	//The image that's loaded
	SDL_Surface* loadedImage = NULL;

	//The optimized surface that will be used
	SDL_Surface* optimizedImage = NULL;

	//Load the image
	loadedImage = SDL_LoadBMP(path);

	//If the image loaded
	if (loadedImage != NULL) {
		//Color key surface
		SDL_SetColorKey(loadedImage, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(loadedImage->format, 185, 243, 182));

		//Create an optimized surface
		optimizedImage = SDL_DisplayFormat(loadedImage);

		//Free the old surface
		SDL_FreeSurface(loadedImage);
	}

	//Return the optimized surface
	return optimizedImage;
}

/////////////////////////////////////////////////////////////////////////////////////////

Torneo* AdministradorEstadisticas::getTorneo() {
	return torneo;
}

void AdministradorEstadisticas::setTorneo(Torneo* torneo) {
	this->torneo = torneo;
}
